package com.ce.pms.charge.service.impl;


import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.ce.pms.base.service.impl.PmsBaseServiceImpl;
import com.ce.pms.charge.dao.IDebitTransDao;
import com.ce.pms.charge.dao.IMeterDataRegisterDao;
import com.ce.pms.charge.dao.IPeriodDao;
import com.ce.pms.charge.model.AbstractSubAccount;
import com.ce.pms.charge.model.ChargeDatasDomain;
import com.ce.pms.charge.model.DebitTransDomain;
import com.ce.pms.charge.model.PeriodDomain;
import com.ce.pms.charge.service.IMeterDataRegisterService;
import com.ce.pms.charge.vo.OriginalMeterDataVO;
import com.ce.pms.common.annotation.AssociatedPrecinctQuery;
import com.ce.pms.common.model.SysInfo;
import com.ce.pms.common.model.SysrefcodeDO;
import com.ce.pms.customer.dao.IProRightDao;
import com.ce.pms.customer.model.ProRightDO;
import com.ce.pms.exception.BusinessException;
import com.ce.pms.house.dao.IGoOutDao;
import com.ce.pms.house.dao.IHouseDao;
import com.ce.pms.house.dao.IMeterDao;
import com.ce.pms.house.model.HouseDomain;
import com.ce.pms.house.model.MeterDomain;
import com.ce.util.BlankUtil;
import com.sitechasia.webx.core.support.Page;
import com.sitechasia.webx.core.utils.base.PopulateUtil;
/**
 * 功能描述: 走表数据录入功能处理类
 * <p>版权所有：中企动力
 * <p>未经本公司许可，不得以任何方式复制或使用本程序任何部分
 *
 * @author  胡煦
 * Create on:2008-8-13
 * Edit author:
 * Edit on:
 * 修改原因：

 */
public class MeterDataRegisterServiceImpl extends PmsBaseServiceImpl implements
		IMeterDataRegisterService{

	/**
	 * 方法描述: 根据房屋ID查询是否有抄表数据方法
	 * @author 胡煦
	 * Create on:2008-8-13
	 * @param houseId
	 * @return boolean 当有抄表数据时返回true,否则返回false
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public boolean checkMeterDataByHouseId(Long houseId){
		super.checkParameterIsNull(houseId,
				"common:parameters_null_exception,ID");
		return meterDataRegisterDao.getMeterDatasListByHouseId(houseId) != null;

	}

	/**
	 * 方法描述: 根据房屋ID查询抄表数据VO列表方法
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param houseId
	 * @return List<OriginalMeterDataVO>
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public List<OriginalMeterDataVO> findMeterDataVOListByHouseId(Long houseId){
		super.checkParameterIsNull(houseId,
				"common:parameters_null_exception,ID");
		List<OriginalMeterDataVO> originalMeterDataVOlist = new ArrayList<OriginalMeterDataVO>();
		List<ChargeDatasDomain> chargeDatasDomainlist = meterDataRegisterDao.getMeterDatasListByHouseId(houseId);
		for(ChargeDatasDomain chargeDatasDomain : chargeDatasDomainlist){
			OriginalMeterDataVO originalMeterDataVO = this.convertChargeDatasD2V(chargeDatasDomain);
			originalMeterDataVOlist.add(originalMeterDataVO);
		}
		return originalMeterDataVOlist;

	}

	/**
	 * 方法描述: 查询所有收费周期列表
	 * @author 胡煦
	 * Create on:2008-8-29
	 * @param
	 * @return List<PeriodDomain>
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	@AssociatedPrecinctQuery(alias = "period", beginStr = " AND ", endStr = " ", insertAfterPoint = "WHERE 1=1",property4Precinct="chargePrecinct.keyword")
	public List<PeriodDomain> getAllPeriodDo(){
		return periodDao.findAllResult("from PeriodDomain period WHERE 1=1", null);
	}


	/**
	 * 方法描述: 根据房号查询某个收费周期下有效的水表和电表的抄表数据VO
	 * @author 胡煦
	 * Create on:2008-8-18
	 * @param houseNumber
	 * @return Map<String, OriginalMeterDataVO>
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public Map<String, OriginalMeterDataVO> findMeterDataVOBy(String houseNumber){
		houseNumber = houseNumber.trim();
		Map<String, OriginalMeterDataVO> map = new HashMap<String, OriginalMeterDataVO>();
		HouseDomain houseDomain = (HouseDomain)houseDao.getHouseDomainByHouseNumber(houseNumber);
		//水表OriginalMeterDataVO
		OriginalMeterDataVO waterMeterDataVO = this.findMeterDataVOByHouseNumber(houseNumber, SysrefcodeDO.HM_WATER_METER_TYPE_CODE);
		//当原始数据中为空时，取走表底数
		if(BlankUtil.isBlank(waterMeterDataVO.getMeterType())){
			map.put("001", getMeterBaseForMeterDataVOBy(waterMeterDataVO, houseDomain.getKeyword(), SysrefcodeDO.HM_WATER_METER_TYPE_CODE));
		}else{
			map.put("001", waterMeterDataVO);
		}
		//电表OriginalMeterDataVO
		OriginalMeterDataVO ammeterMeterDataVO  =this.findMeterDataVOByHouseNumber(houseNumber, SysrefcodeDO.HM_AMMETER_METER_TYPE_CODE);
		//当原始数据中为空时，取走表底数
		if(BlankUtil.isBlank(ammeterMeterDataVO.getMeterType())){
			map.put("002", getMeterBaseForMeterDataVOBy(ammeterMeterDataVO, houseDomain.getKeyword(), SysrefcodeDO.HM_AMMETER_METER_TYPE_CODE));
		}else{
			map.put("002", ammeterMeterDataVO);
		}
		return map;
	}

	/**
	 * 方法描述: 根据id查询抄表数据VO
	 * @author 胡煦
	 * Create on:2008-8-18
	 * @param ID
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO findMeterDataVOByID(Long meterDataId){

		OriginalMeterDataVO mterDataVO  = convertChargeDatasD2V( meterDataRegisterDao.findById(meterDataId));

		return mterDataVO;
	}


	/**
	 *
	 * 功能描述: 通过收费周期id查询新建状态的走表实体List
	 *
	 * @author 胡煦
	 * Created on:2008-8-27
	 *
	 * 修改原因：
	 * @param periodId
	 * @return List<OriginalMeterDataVO> 返回结果
	 */
	public List<OriginalMeterDataVO> getMeterDatasListByPeriodId(Long periodId){

		List<OriginalMeterDataVO> originalMeterDataVOlist = new ArrayList<OriginalMeterDataVO>();
		List<ChargeDatasDomain> chargeDatasDomainlist = meterDataRegisterDao.getMeterDatasListByPeriodId(periodId);
		for(ChargeDatasDomain chargeDatasDomain : chargeDatasDomainlist){
			OriginalMeterDataVO originalMeterDataVO = this.convertChargeDatasD2V(chargeDatasDomain);
			originalMeterDataVOlist.add(originalMeterDataVO);
		}
		return originalMeterDataVOlist;
	}


	/**
	 * 方法描述: 根据房号和走表类型查询某个收费周期下有效的抄表数据VO
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param houseId,meterTypeCode
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO findMeterDataVOByHouseNumber(String houseNumber,String meterTypeCode){
		HouseDomain houseDomain = (HouseDomain)houseDao.getHouseDomainByHouseNumber(houseNumber.trim());
		OriginalMeterDataVO originalMeterDataVO = new OriginalMeterDataVO();
		ChargeDatasDomain chargeDatasDoma = meterDataRegisterDao.getMeterDatasListByHouseIdAndType(houseDomain.getKeyword(), meterTypeCode);
		if(BlankUtil.isBlank(chargeDatasDoma)){
			return getMeterBaseForMeterDataVOBy(originalMeterDataVO, houseDomain.getKeyword(), meterTypeCode);
		}
		return this.convertChargeDatasD2V(chargeDatasDoma);
	}

	/**
	 * 方法描述: 根据ID查找走表原始数据VO
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param meterDataid
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO findMeterDataVOById(Long meterDataid){
		super.checkParameterIsNull(meterDataid,
		"common:parameters_null_exception,ID");
		return this.convertChargeDatasD2V(meterDataRegisterDao.findById(meterDataid));

	}

	/**
	 * 方法描述: 验证作废操作的合法性
	 * @author 胡煦
	 * Create on:2008-10-16
	 * @param meterDataid
	 * @return ChargeDatasDomain
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public ChargeDatasDomain checkabateMeterDataState(Long meterDataid){
		ChargeDatasDomain domain = meterDataRegisterDao.findById(meterDataid);
		//当前收费周期该走表数据对应的状态为“新建”才能执行作废走表数据操作
		if(!domain.getStatuz().equals(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_NEW)){
			throw new BusinessException("charge:charge_meter_abate_not_exception", BusinessException.WARNING);
		}
		return domain;
	}

	/**
	 * 方法描述: 根据ID作废走表原始数据
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param meterDataid,creatorId
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO abateMeterDataById(Long meterDataid,Long creatorId){
		super.checkParameterIsNull(meterDataid,
		"common:parameters_null_exception,ID");

		ChargeDatasDomain domain = this.checkabateMeterDataState(meterDataid);

		modifyInfo(domain.getSysInfo(), creatorId);

		domain.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_ABATE);
		return this.convertChargeDatasD2V(domain);
	}

//	/**
//	 * 方法描述: 根据ID修改或调整某条走表读数
//	 * @author 胡煦
//	 * Create on:2008-8-15
//	 * @param originalMeterDataVO
//	 * @return originalMeterDataVO
//	 * Edit author:
//	 * Edit on:
//	 * 修改原因：
//	 */
//	public OriginalMeterDataVO editOrAdjustOriginalMeterDataBy(OriginalMeterDataVO originalMeterDataVO){
//		ChargeDatasDomain domain = meterDataRegisterDao.findById(originalMeterDataVO.getChargeDataId());
//		//获取指定房间对应的一系列属性
//		BigDecimal thisReading = originalMeterDataVO.getThisReading();
//		PopulateUtil.populate(domain, originalMeterDataVO);
//		originalMeterDataVO.setHouseId(domain.getHouse().getKeyword());
//		originalMeterDataVO.setThisReading(thisReading);
//		originalMeterDataVO.setMeterType(domain.getMeter().getMeterType().getCode());
//		originalMeterDataVO.setMeterName(domain.getMeter().getMeterType().getName());
//		originalMeterDataVO.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_EDIT);
//		//获取当前收费周期该走表数据对应的收费交易
//		DebitTransDomain debitTransDomain = debitTransDao.getTransDomainBy(originalMeterDataVO.getChargeDataId());
//		if(!BlankUtil.isBlank(debitTransDomain)){
//			String statuz = debitTransDomain.getStatuz();
//			//当前收费周期该走表数据对应的收费交易为“已缴费”或“全额减免”状态才能执行调整走表数据操作
//			if(statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_PAYED)||
//					statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_DERATE)){
//				modifyInfo(domain.getSysInfo(), originalMeterDataVO.getCreator());
//				domain.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_ADJUST);
//				originalMeterDataVO = this.addOriginalMeterData(originalMeterDataVO);
//				return originalMeterDataVO;
//			}else{
//				return this.editOriginalMeterDataBy(originalMeterDataVO);
//			}
//		}else
//			return this.editOriginalMeterDataBy(originalMeterDataVO);
//	}

	/**
	 * 方法描述: 验证调整的原始数据是否满足条件
	 * @author 胡煦
	 * Create on:2008-10-16
	 * @param chargeDataId
	 * @return Map
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public ChargeDatasDomain checkAjustMeterDataState(Long chargeDataId){
		ChargeDatasDomain chargeDatasDomain = meterDataRegisterDao.findById(chargeDataId);
		List<DebitTransDomain> debitTransDomains = debitTransDao.getTransDomainBy(chargeDataId);

		//只有已计算状态才能执行调整操作
		if(!SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_COUNTED.equals(chargeDatasDomain.getStatuz())){
			throw new BusinessException("charge:charge_meter_adjust_only_exception", BusinessException.WARNING);
		}
		// 对应的收费交易为“已缴费”或“全额减免”状态才能执行调整操作
		if(!BlankUtil.isBlank(debitTransDomains)){
			for(DebitTransDomain debitTransDomain : debitTransDomains){
				String statuz = debitTransDomain.getStatuz();
				if(!(statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_PAYED)||
							statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_DERATE))){
					throw new BusinessException("charge:charge_meter_adjust_tran_only_exception", BusinessException.WARNING);
				}
			}
		}
		return chargeDatasDomain;
	}


	/**
	 * 方法描述: 调整走表读数
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param originalMeterDataVO
	 * @return originalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO adjustMeterData(OriginalMeterDataVO originalMeterDataVO){

		ChargeDatasDomain domain  = this.checkAjustMeterDataState(originalMeterDataVO.getChargeDataId());
		//验证走表读数不能大于归零值
		checkMeterDataCZero(originalMeterDataVO.getThisReading(), domain.getMeter().getMeterType().getCode());
		//获取指定房间对应的一系列属性
		BigDecimal thisReading = originalMeterDataVO.getThisReading();
		PopulateUtil.populate(domain, originalMeterDataVO);
		originalMeterDataVO.setHouseId(domain.getHouse().getKeyword());
		originalMeterDataVO.setThisReading(thisReading);
		originalMeterDataVO.setMeterType(domain.getMeter().getMeterType().getCode());
		originalMeterDataVO.setMeterName(domain.getMeter().getMeterType().getName());
		//originalMeterDataVO.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_EDIT);
		modifyInfo(domain.getSysInfo(), originalMeterDataVO.getModifier());
		domain.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_ADJUST);
		originalMeterDataVO.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_COUNTED);
		originalMeterDataVO.setCreator(originalMeterDataVO.getModifier());
		originalMeterDataVO.setChargeDataId(null);
		originalMeterDataVO = this.addOriginalMeterData(originalMeterDataVO);

		return originalMeterDataVO;
	}


	/**
	 * 方法描述: 新增某条走表读数
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param originalMeterDataVO
	 * @return originalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO addOriginalMeterData(OriginalMeterDataVO originalMeterDataVO){

		this.checkChargeDatasVONotNullField(originalMeterDataVO, "common:mustFill_null_exception");
		//获取业主姓名字符串
		//originalMeterDataVO.setOwners(this.getOwnersByHouseId(originalMeterDataVO.getHouseId()));
		//版本状态设为新增
		originalMeterDataVO.setStatuz(originalMeterDataVO.getStatuz()==null?SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_NEW:originalMeterDataVO.getStatuz());
		//获取指定房间对应的一系列属性
		ChargeDatasDomain chargeDatasDomain = setOriginalMeterDataVOByhouseId(originalMeterDataVO);
		chargeDatasDomain.setOwners(originalMeterDataVO.getOwners());
		chargeDatasDomain = meterDataRegisterDao.saveObject(chargeDatasDomain);
		originalMeterDataVO.setChargeDataId(chargeDatasDomain.getChargeDataId());
		originalMeterDataVO.setMeterId(chargeDatasDomain.getMeter().getKeyword());
		return originalMeterDataVO;

	}

	/**
	 * 方法描述: 修改某条走表读数,根据originalMeterDataVO中的ID是否为空进行不同处理
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param originalMeterDataVO
	 * @return originalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private OriginalMeterDataVO editOriginalMeterData(OriginalMeterDataVO originalMeterDataVO,ChargeDatasDomain domain,List<DebitTransDomain> debitTransDomains){

			//如果本次读数不为空，说明是修改，先把原来的版本状态改为修改作废，然后新增；否则直接进行交易修改操作
			if(!BlankUtil.isBlank(originalMeterDataVO.getThisReading())){
				//ChargeDatasDomain domain = meterDataRegisterDao.findById(originalMeterDataVO.getChargeDataId());
//				//获取抄表数据记录
//				CopyMeterData copyMeterData = copyMeterDataDao.queryCopyMeterDataBy(originalMeterDataVO.getChargeDataId());
//				copyMeterData.setReading(originalMeterDataVO.getThisReading());
//				modifyInfo(copyMeterData.getSysInfo(), originalMeterDataVO.getCreator());
				//获取指定房间对应的一系列属性
				originalMeterDataVO.setHouseId(domain.getHouse().getKeyword());
				originalMeterDataVO.setOwners(domain.getOwners());
				originalMeterDataVO.setLastReading(domain.getLastReading());
				originalMeterDataVO.setRecordTime(originalMeterDataVO.getRecordTime()==null?domain.getRecordTime():originalMeterDataVO.getRecordTime());
				originalMeterDataVO.setRemark(domain.getRemark());
				originalMeterDataVO.setMeterType(domain.getMeter().getMeterType().getCode());
				modifyInfo(domain.getSysInfo(), originalMeterDataVO.getCreator());
			}
			//把原来的版本状态改为修改作废
			domain.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_EDIT);
				//找到将要被删除的交易
				//DebitTransDomain debitTransDomain = debitTransDao.getTransDomainBy(originalMeterDataVO.getChargeDataId());
				if(!BlankUtil.isBlank(debitTransDomains)){
					for(DebitTransDomain debitTransDomain : debitTransDomains){
						Set<ChargeDatasDomain> chargeDatasSet = debitTransDomain.getChargeDatas();
						for(ChargeDatasDomain datasDomain : chargeDatasSet){
							if(!datasDomain.getChargeDataId().equals(domain.getChargeDataId())){
								datasDomain.setStatuz(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_NEW);
							}
						}
						debitTransDao.saveOrUpdateObject(debitTransDomain);
						if(!BlankUtil.isBlank(debitTransDomain)){
							//调整子帐户中的余额：原来的BALANCE减去将要被删除的交易的DEBIT
							AbstractSubAccount bindingAccount = debitTransDomain.getBindingAccount();
							if(!BlankUtil.isBlank(bindingAccount)){
								BigDecimal balance = debitTransDomain.getBindingAccount().getBalance().subtract(debitTransDomain.getDebit());
								bindingAccount.setBalance(balance);
							}

							//删除子帐户交易及原始数据与子帐户交易的对应关系
							debitTransDao.deleteObject(debitTransDomain);
						}
					}

				}

			originalMeterDataVO.setChargeDataId(null);

		return originalMeterDataVO;
	}

	/**
	 * 方法描述: 修改某条走表读数，进行了抄表数据的验证
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param originalMeterDataVO
	 * @return originalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO editOriginalMeterDataDoCheck(OriginalMeterDataVO originalMeterDataVO){
		//this.checkChargeDataHasCopyDoing(originalMeterDataVO.getChargeDataId());
		return this.editOriginalMeterDataBy(originalMeterDataVO,false);
	}

	/**
	 * 方法描述: 验证修改的原始数据是否合法
	 * @author 胡煦
	 * Create on:2008-10-16
	 * @param chargeDataId,isDoGoOut:为true时说明是产权变更调用，否则为走表数据录入所用
	 * @return Map
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public Map checkEditMeterDataState(Long chargeDataId,boolean isDoGoOut){

		ChargeDatasDomain chargeDatasDomain = meterDataRegisterDao.findById(chargeDataId);
		PeriodDomain nowPeriod = periodDao.findAvailPeriodBy(chargeDatasDomain.getHouse().getBuilding().getKeyword());

		//只有当前收费周期的数据才能修改
		if(BlankUtil.isBlank(nowPeriod)||!nowPeriod.equals(chargeDatasDomain.getPeriod())){
			throw new BusinessException("charge:charge_meter_edit_perid_mustnow_exception", BusinessException.WARNING);
		}
		List<DebitTransDomain> debitTransDomains = debitTransDao.getTransDomainBy(chargeDataId);
		Map map = new HashMap();
		if(!isDoGoOut){
			//进行是否产生抄表数据的验证
			checkChargeDataHasCopyDoing(chargeDatasDomain.getHouse().getKeyword());
		}
		//只有新建或已计算状态才能修改
		if(!(chargeDatasDomain.getStatuz().equals(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_NEW )||chargeDatasDomain.getStatuz().equals(SysrefcodeDO.FEE_CHARGE_DATAS_STATUS_COUNTED))){
			throw new BusinessException("charge:charge_meter_edit_must_exception", BusinessException.WARNING);
		}
		if(!BlankUtil.isBlank(debitTransDomains)){
			for(DebitTransDomain debitTransDomain : debitTransDomains){
				//存在附属交易，不允许修改
				if(debitTransDomain.getTraRtras().size()>0){
					throw new BusinessException("charge:charge_meter_edit_hastran_exception", BusinessException.WARNING);
				}
				String statuz = debitTransDomain.getStatuz();
				//如果对应的收费交易已经缴费或者处于挂起、出盘锁定，全额减免状态，不能修改
				if(statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_PAYED)||
						statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_HANGED)||
							statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_LOCKED)||
								statuz.equals(SysrefcodeDO.FEE_TRANSACTION_STATUZ_DERATE)){
					throw new BusinessException("charge:charge_meter_edit_not_exception", BusinessException.WARNING);
				}
			}

		}
		map.put("chargeDatasDomain", chargeDatasDomain);
		map.put("debitTransDomains", debitTransDomains);
		return map;
	}

	/**
	 * 方法描述: 修改某条走表读数，根据不同的状态进行不同的处理
	 * @author 胡煦
	 * Create on:2008-8-15
	 * @param originalMeterDataVO，isDoGoOut:为true时说明是产权变更调用，否则为走表数据录入所用
	 * @return originalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public OriginalMeterDataVO editOriginalMeterDataBy(OriginalMeterDataVO originalMeterDataVO,boolean isDoGoOut){

		Map map = this.checkEditMeterDataState(originalMeterDataVO.getChargeDataId(),isDoGoOut);
		ChargeDatasDomain chargeDatasDomain = (ChargeDatasDomain) map.get("chargeDatasDomain");
		//验证走表读数不能大于归零值
		checkMeterDataCZero(originalMeterDataVO.getThisReading(), chargeDatasDomain.getMeter().getMeterType().getCode());

		List<DebitTransDomain> debitTransDomains =  (List<DebitTransDomain>) map.get("debitTransDomains");
		//进行修改相关的业务操作
		originalMeterDataVO = this.editOriginalMeterData(originalMeterDataVO,chargeDatasDomain,debitTransDomains);
		if(!BlankUtil.isBlank(originalMeterDataVO.getThisReading())){
			//新增修改后的记录
			originalMeterDataVO = this.addOriginalMeterData(originalMeterDataVO);
		}

		return originalMeterDataVO;
	}

	/**
	 * 方法描述: 按户录入走表读数
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param Set<OriginalMeterDataVO>
	 * @return Set<OriginalMeterDataVO>
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public Set<OriginalMeterDataVO> registerMeterDataByDoor(Set<OriginalMeterDataVO> meterDataVOSet){

		Set<OriginalMeterDataVO> set = new HashSet<OriginalMeterDataVO>();

		for(OriginalMeterDataVO meterDataVO : meterDataVOSet){

			this.checkChargeDatasVONotNullField(meterDataVO, "common:mustFill_null_exception");

			meterDataVO = this.addOriginalMeterData(meterDataVO);

			set.add(meterDataVO);
		}

		return set;
	}

	/**
	 * 方法描述: 分页组合查询抄表数据方法
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param OriginalMeterDataVO
	 * @return Page
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public Page getChargeDatasVOsByPage(OriginalMeterDataVO queryDataVO ,int currentPage,int pageSize){

		Page page = meterDataRegisterDao.getChargeDatasDomainsByPage(new Conditions(queryDataVO.getBuildingId(),queryDataVO.getProRightId(), queryDataVO.getRecordTime(),
				queryDataVO.getMeterId(), queryDataVO.getPeriodId(), queryDataVO.getStatuz(),queryDataVO.getHouseId(),queryDataVO.getHouseIds(),
				queryDataVO.getHouseNumber(),queryDataVO.getOrder()),currentPage,pageSize);
		List<ChargeDatasDomain> chargeDatasDolist = page.getResult();
		List<OriginalMeterDataVO> meterDataVOlist = new ArrayList<OriginalMeterDataVO>();
		for(ChargeDatasDomain datasDomain : chargeDatasDolist){
			OriginalMeterDataVO meterDataVO = this.convertChargeDatasD2V(datasDomain);
			meterDataVOlist.add(meterDataVO);
		}
		page.setResult(meterDataVOlist);
		return page;
	}
//	/**
//	 * 方法描述:根据走表类型CODE查询走表归零值
//	 * @author 胡煦
//	 * Create on:2008-11-3
//	 * @param meterTypeCode
//	 * @return String
//	 * Edit author:
//	 * Edit on:
//	 * 修改原因：
//	 */
//	public String findMaxNumberByCode(String meterTypeCode){
//		//根据走表类型CODE查询走表归零值
//		return meterMaxMap.get(meterTypeCode).toString();
//	}

	/**
	 * 方法描述: 检查某房屋是否处于退伙中
	 * @author 胡煦
	 * Create on:2008-10-6
	 * @param chargeDataId
	 * @return ture:说明处于退伙中，false:说明不存在
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private boolean checkChargeDataHasCopy(Long houseId){
		return goOutDao.queryHouseInGoOutBy(houseId) != null;
	}

	/**
	 * 方法描述: 验证走表读数不能大于归零值
	 * @author 胡煦
	 * Create on:2008-10-16
	 * @param thisReading,meterTypeCode
	 * @return void
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private void checkMeterDataCZero(BigDecimal thisReading,String meterTypeCode){
		BigInteger waterMaxz = (BigInteger) meterMaxMap.get(meterTypeCode);
		if(thisReading.doubleValue() > waterMaxz.doubleValue()){
			throw new BusinessException("charge:charge_meter_inpit_error_exception,"
					+ waterMaxz.doubleValue(), BusinessException.WARNING);
		}
	}

	/**
	 * 方法描述: 根据走表原始数据ID验证其是否存在抄表数据
	 * @author 胡煦
	 * Create on:2008-10-6
	 * @param chargeDataId
	 * @return ture:说明存在抄表数据，false:说明不存在
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public void checkChargeDataHasCopyDoing(Long houseId){
		if(checkChargeDataHasCopy(houseId)){
			throw new BusinessException("charge:charge_meterDataRegister_copyData_existed", BusinessException.WARNING);
		}
	}


	/**
	 * 方法描述: 根据房屋ID和走表类型code设置相关走表原始数据属性
	 * @author 胡煦
	 * Create on:2008-8-19
	 * @param houseId
	 * @return ChargeDatasDomain
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private OriginalMeterDataVO getMeterBaseForMeterDataVOBy(OriginalMeterDataVO originalMeterDataVO,Long houseId,String meterTypeCode){
		MeterDomain meterDomain = this.checkMeterByHouseIdAndCode(houseId, meterTypeCode);
		originalMeterDataVO.setHouseId(houseId);
		originalMeterDataVO.setMAXZ(new BigDecimal( meterMaxMap.get(meterTypeCode).toString()));;
		originalMeterDataVO.setThisReading(meterDomain.getBase());
		originalMeterDataVO.setMeterType(meterTypeCode);
		return originalMeterDataVO;
	}
	/**
	 * 方法描述: 根据房屋ID设置相关走表原始数据属性
	 * @author 胡煦
	 * Create on:2008-8-19
	 * @param houseId
	 * @return ChargeDatasDomain
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private ChargeDatasDomain setOriginalMeterDataVOByhouseId(OriginalMeterDataVO originalMeterDataVO){

		super.checkParameterIsNull(originalMeterDataVO.getHouseId(),
		"common:parameters_null_exception,ID");

		HouseDomain houseDomain = houseDao.findById(originalMeterDataVO.getHouseId());
		PeriodDomain periodDomain = periodDao.findAvailPeriodBy(houseDomain.getBuilding().getKeyword());
		if(BlankUtil.isBlank(periodDomain)){
			throw new BusinessException("charge:charge_meterDataRegister_period_notexisted", BusinessException.WARNING);
		}
		ProRightDO proRightDO = proRightDao.getEffectiveProRightByHouseId(originalMeterDataVO.getHouseId());
		MeterDomain meterDomain = checkMeterByHouseIdAndCode(originalMeterDataVO.getHouseId(),originalMeterDataVO.getMeterType());
		originalMeterDataVO.setMeterId(meterDomain.getKeyword());
		ChargeDatasDomain chargeDatasDomain = convertChargeDatasV2D(originalMeterDataVO);
		chargeDatasDomain.setHouse(houseDomain);
		chargeDatasDomain.setMeter(meterDomain);
		chargeDatasDomain.setPeriod(periodDomain);
		chargeDatasDomain.setProRight(proRightDO);

		return chargeDatasDomain;

	}



	/**
	 * 方法描述: ChargeDatasDomain to OriginalMeterDataVO
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param ChargeDatasDomain
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private OriginalMeterDataVO convertChargeDatasD2V(ChargeDatasDomain chargeDatasDomain){
		OriginalMeterDataVO meterDataVO = new OriginalMeterDataVO();
		if(BlankUtil.isBlank(chargeDatasDomain)){
			return meterDataVO;
		}
		PopulateUtil.populate(chargeDatasDomain, meterDataVO);
		meterDataVO.setMeterType(chargeDatasDomain.getMeter() ==null?null:chargeDatasDomain.getMeter().getMeterType().getCode());
		meterDataVO.setMeterName(chargeDatasDomain.getMeter() ==null?null:chargeDatasDomain.getMeter().getName());
		meterDataVO.setHouseId(chargeDatasDomain.getHouse() ==null?null:chargeDatasDomain.getHouse().getKeyword());
		meterDataVO.setHouseNumber(chargeDatasDomain.getHouse() ==null?null:chargeDatasDomain.getHouse().getHouseNumber());
		meterDataVO.setMeterId(chargeDatasDomain.getMeter() ==null?null:chargeDatasDomain.getMeter().getKeyword());
		meterDataVO.setPeriodId(chargeDatasDomain.getPeriod() ==null?null:chargeDatasDomain.getPeriod().getKeyword());
		meterDataVO.setPeriodDate(chargeDatasDomain.getPeriod() ==null?null:chargeDatasDomain.getPeriod().getPeriod());
		meterDataVO.setProRightId(chargeDatasDomain.getProRight() ==null?null:chargeDatasDomain.getProRight().getProRightId());
		//meterDataVO.setTransactionId(chargeDatasDomain.getTransaction() ==null?null:chargeDatasDomain.getTransaction().getTransactionId());
		meterDataVO.setCreator(chargeDatasDomain.getSysInfo()==null?null:chargeDatasDomain.getSysInfo().getCreator());
		meterDataVO.setModifier(chargeDatasDomain.getSysInfo()==null?null:chargeDatasDomain.getSysInfo().getModifier());
		meterDataVO.setModifyDate(chargeDatasDomain.getSysInfo()==null?null:chargeDatasDomain.getSysInfo().getModifyDate());
		meterDataVO.setSysDate(chargeDatasDomain.getSysInfo()==null?null:chargeDatasDomain.getSysInfo().getSysDate());
		meterDataVO.setMAXZ(new BigDecimal( meterMaxMap.get(meterDataVO.getMeterType()).toString()));
		return meterDataVO;
	}
	/**
	 * 方法描述: 计算用量，本次读数〉上次读数，则=（本次读数-上次读数）本次读数<上次读数,则=（归零数-上次读数+本次读数）
	 * @author 胡煦
	 * Create on:2008-8-25
	 * @param lastReading，thisReading，meterId
	 * @return BigDecimal
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public BigDecimal countWastage(BigDecimal lastReading,BigDecimal thisReading ,Long meterId){
		BigDecimal wastage = null;
		if(lastReading.doubleValue() > thisReading.doubleValue()){
			MeterDomain meterDomain = meterDao.findById(meterId);
			//根据走表类型CODE查询走表归零值
			BigInteger MAXZ = (BigInteger) meterMaxMap.get(meterDomain.getMeterType().getCode());
			//如果归零值为空或者小于零的话，则抛出非法异常
			if(BlankUtil.isBlank(MAXZ)||MAXZ.doubleValue() < 0){
				throw new BusinessException("charge:charge_meter_base_error_exception", BusinessException.WARNING);
			}
			wastage = new BigDecimal(MAXZ.doubleValue() -
					lastReading.doubleValue() +
					thisReading.doubleValue());
			}else{
			wastage =new BigDecimal(thisReading.doubleValue() -
					lastReading.doubleValue());
			}
		return wastage;
	}




	/**
	 * 方法描述: ChargeDatasDomain to OriginalMeterDataVO
	 * @author 胡煦
	 * Create on:2008-8-14
	 * @param ChargeDatasDomain
	 * @return OriginalMeterDataVO
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	private ChargeDatasDomain convertChargeDatasV2D(OriginalMeterDataVO originalMeterDataVO){
		ChargeDatasDomain chargeDatasDomain = new ChargeDatasDomain();
		if(BlankUtil.isBlank(originalMeterDataVO)){
			return chargeDatasDomain;
		}
		PopulateUtil.populate(originalMeterDataVO, chargeDatasDomain);
		if(!BlankUtil.isBlank(originalMeterDataVO.getLastReading())&&!BlankUtil.isBlank(originalMeterDataVO.getThisReading())){
			//计算用量，本次读数〉上次读数，则=（本次读数-上次读数）本次读数<上次读数,则=（归零数-上次读数+本次读数）
			BigDecimal wastage = countWastage(originalMeterDataVO.getLastReading(),originalMeterDataVO.getThisReading(),originalMeterDataVO.getMeterId());
			chargeDatasDomain.setWastage(wastage);
		}
		if (!BlankUtil.isBlank(originalMeterDataVO.getCreator())) {
			SysInfo sysInfo = createInfo(originalMeterDataVO.getCreator());
			chargeDatasDomain.setSysInfo(sysInfo);
		}

		return chargeDatasDomain;
	}

	/**
	 * 方法描述: 根据房屋ID和表类型验证是否有该表
	 * @author 胡煦
	 * Create on:2008-8-13
	 * @param houseId
	 * @return MeterDomain
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public MeterDomain checkMeterByHouseIdAndCode(Long houseId,String meterType){
		super.checkParameterIsNull(houseId,
				"common:parameters_null_exception,ID");
		MeterDomain meterDomain = meterDao.getMeterByHouseId(houseId,meterType);
		if(BlankUtil.isBlank(meterDomain)&&SysrefcodeDO.HM_WATER_METER_TYPE_CODE.equals(meterType)){
			throw new BusinessException("charge:charge_meterDataRegister_houseNumber_noexistwater", BusinessException.WARNING);
		}
		if(BlankUtil.isBlank(meterDomain)&&SysrefcodeDO.HM_AMMETER_METER_TYPE_CODE.equals(meterType)){
			throw new BusinessException("charge:charge_meterDataRegister_houseNumber_noexistammeter", BusinessException.WARNING);
		}
		return meterDomain;
	}

//	/**
//	 * 方法描述: 根据房屋ID找到其下所有业主，并将他们姓名用逗号隔开返回
//	 * @author 胡煦
//	 * Create on:2008-8-15
//	 * @param houseId
//	 * @return String
//	 * Edit author:
//	 * Edit on:
//	 * 修改原因：
//	 */
//	private String getOwnersByHouseId(Long houseId){
//		super.checkParameterIsNull(houseId,
//		"common:parameters_null_exception,ID");
//		List<ParticipantDO> clientDOlist = null;
//		clientDOlist = clientRHouseDao.getAllOwnerByHouseId(houseId);
//		StringBuffer ownerNames = new StringBuffer();
//		for(ParticipantDO participantDO : clientDOlist){
//			ownerNames.append(participantDO.getParticipantName());
//			ownerNames.append(",");
//		}
//		if (ownerNames.length() > 0) {
//			ownerNames.deleteCharAt(ownerNames.length() - 1);
//		}
//		return ownerNames.toString();
//	}

	private void setMap(){
		meterMaxMap = new HashMap();
		BigInteger waterMaxz = meterDao.getMAXZByMeterTypeCode("001");
		BigInteger ammerMaxz = meterDao.getMAXZByMeterTypeCode("002");
		BigInteger oilMaxz = meterDao.getMAXZByMeterTypeCode("003");
		meterMaxMap.put("001", waterMaxz);
		meterMaxMap.put("002", ammerMaxz);
		meterMaxMap.put("003", oilMaxz);
	}

	/**
	 * 方法描述: 检查抄表数据版本VO中必填项是否为空
	 *
	 * @author 胡煦 Create on:2008-8-15
	 * @param OriginalMeterDataVO,key
	 * @return void Edit author: Edit on: 修改原因：
	 */
	private void checkChargeDatasVONotNullField(
			OriginalMeterDataVO meterDataVO, String key) {
		if (meterDataVO.getHouseId() == null
				|| meterDataVO.getThisReading() == null
				|| meterDataVO.getRecordTime() == null) {
			throw new BusinessException(key, BusinessException.WARNING);
		}
	}

	private IMeterDataRegisterDao meterDataRegisterDao;
	private IHouseDao houseDao;
	private IMeterDao meterDao;
	private IPeriodDao periodDao;
	private IProRightDao proRightDao;
	private IDebitTransDao debitTransDao;
	private IGoOutDao goOutDao;
	private Map meterMaxMap;


	/**
	 * @param meterDataRegisterDao the meterDataRegisterDao to set
	 */
	public void setMeterDataRegisterDao(IMeterDataRegisterDao meterDataRegisterDao) {
		this.meterDataRegisterDao = meterDataRegisterDao;
	}

	/**
	 * @param debitTransDao the debitTransDao to set
	 */
	public void setDebitTransDao(IDebitTransDao debitTransDao) {
		this.debitTransDao = debitTransDao;
	}

	/**
	 * @param houseDao the houseDao to set
	 */
	public void setHouseDao(IHouseDao houseDao) {
		this.houseDao = houseDao;
	}

	/**
	 * @param meterDao the meterDao to set
	 */
	public void setMeterDao(IMeterDao meterDao) {
		this.meterDao = meterDao;
		setMap();
	}

	/**
	 * @param periodDao the periodDao to set
	 */
	public void setPeriodDao(IPeriodDao periodDao) {
		this.periodDao = periodDao;
	}

	/**
	 * @param proRightDao the proRightDao to set
	 */
	public void setProRightDao(IProRightDao proRightDao) {
		this.proRightDao = proRightDao;
	}

	public static class Conditions{
		private Long buildingId;
		private Date recordTime;
		private Long meterTypeId;
		private Long periodId;
		private String statuz;
		private Long houseId;
		private String houseIds;
		private String houseNumber;
		private String order ;
		private Long proRightId;
		public Conditions(Long buildingId,Long proRightId, Date recordTime, Long meterTypeId, Long periodId, String statuz, Long houseId, String houseIds, String houseNumber, String order) {
			super();
			this.buildingId = buildingId;
			this.recordTime = recordTime;
			this.meterTypeId = meterTypeId;
			this.periodId = periodId;
			this.statuz = statuz;
			this.houseId = houseId;
			this.houseIds = houseIds;
			this.houseNumber = houseNumber;
			this.order = order;
			this.proRightId = proRightId;
		}
		public Conditions(Long buildingId,Long proRightId, Date recordTime, Long meterTypeId, Long periodId, String statuz, Long houseId, String houseNumber, String order) {
			super();
			this.buildingId = buildingId;
			this.recordTime = recordTime;
			this.meterTypeId = meterTypeId;
			this.periodId = periodId;
			this.statuz = statuz;
			this.houseId = houseId;
			this.houseNumber = houseNumber;
			this.order = order;
			this.proRightId = proRightId;
		}
		/**
		 * @return the buildingId
		 */
		public Long getBuildingId() {
			return buildingId;
		}
		/**
		 * @param buildingId the buildingId to set
		 */
		public void setBuildingId(Long buildingId) {
			this.buildingId = buildingId;
		}
		/**
		 * @return the houseId
		 */
		public Long getHouseId() {
			return houseId;
		}
		/**
		 * @param houseId the houseId to set
		 */
		public void setHouseId(Long houseId) {
			this.houseId = houseId;
		}
		/**
		 * @return the houseNumber
		 */
		public String getHouseNumber() {
			return houseNumber;
		}
		/**
		 * @param houseNumber the houseNumber to set
		 */
		public void setHouseNumber(String houseNumber) {
			this.houseNumber = houseNumber;
		}
		/**
		 * @return the meterTypeId
		 */
		public Long getMeterTypeId() {
			return meterTypeId;
		}
		/**
		 * @param meterTypeId the meterTypeId to set
		 */
		public void setMeterTypeId(Long meterTypeId) {
			this.meterTypeId = meterTypeId;
		}
		/**
		 * @return the order
		 */
		public String getOrder() {
			return order;
		}
		/**
		 * @param order the order to set
		 */
		public void setOrder(String order) {
			this.order = order;
		}
		/**
		 * @return the periodId
		 */
		public Long getPeriodId() {
			return periodId;
		}
		/**
		 * @param periodId the periodId to set
		 */
		public void setPeriodId(Long periodId) {
			this.periodId = periodId;
		}
		/**
		 * @return the recordTime
		 */
		public Date getRecordTime() {
			return recordTime;
		}
		/**
		 * @param recordTime the recordTime to set
		 */
		public void setRecordTime(Date recordTime) {
			this.recordTime = recordTime;
		}
		/**
		 * @return the statuz
		 */
		public String getStatuz() {
			return statuz;
		}
		/**
		 * @param statuz the statuz to set
		 */
		public void setStatuz(String statuz) {
			this.statuz = statuz;
		}
		public String getHouseIds() {
			return houseIds;
		}
		public void setHouseIds(String houseIds) {
			this.houseIds = houseIds;
		}
		/**
		 * @param proRightId the proRightId to set
		 */
		public void setProRightId(Long proRightId) {
			this.proRightId = proRightId;
		}
		/**
		 * @return the proRightId
		 */
		public Long getProRightId() {
			return proRightId;
		}
	}

	/**
	 * @param goOutDao the goOutDao to set
	 */
	public void setGoOutDao(IGoOutDao goOutDao) {
		this.goOutDao = goOutDao;
	}

}
